24. Exercise: Add a ViewModelFactory

L5 41 Passing In Values To ViewModels SC

***Update note: ***

At timestamp 04:14, the video above shows a now deprecated class ViewModelProviders as

val viewModel = ViewModelProviders.of(this, viewModelFactory).get(ScoreViewModel::class.java).


We have updated the instructions below to use the updated ViewModelProvider class.

Now it’s your turn to complete this exercise yourself.

In this exercise you'll pass data into a ViewModel. You'll create a view model factory that allows you to define a custom constructor for a ViewModel that gets called when you use ViewModelProvider.

You can learn more about the factory pattern here.

1. Create the ScoreViewModel class and have it take in an integer constructor parameter called finalScore:

Make sure to create the ScoreViewModel class file in the same package as the ScoreFragment.

2. Copy over ScoreViewModelFactory:

Create ScoreViewModel factory in the same package as the ScoreFragment. You can use this code later if you ever need to create a view model factory.

Copy the following code:

class ScoreViewModelFactory(private val finalScore: Int) : ViewModelProvider.Factory {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (modelClass.isAssignableFrom(ScoreViewModel::class.java)) {
            // TODO Construct and return the ScoreViewModel
        }
        throw IllegalArgumentException("Unknown ViewModel class")
    }
}

Note that the constructor of your view model factory should take any parameters you want to pass into your ScoreViewModel. In this case, it takes in the final score.

3. In the overridden create method, construct and return an instance of ScoreViewModel, passing in finalScore:

The create method's purpose is to create and return your view model. So you should construct a new ScoreViewModel and return it. You'll also need to deal with the generics, so the statement will be:

return ScoreViewModel(finalScore) as T

4. Create and construct a ScoreViewModelFactory:

In ScoreFragment, create viewModelFactory from ScoreViewModelFactory. For example:

viewModelFactory = ScoreViewModelFactory(<final score here>)

Remember, you need to pass in the final score. It gets passed through with the ScoreFragmentArgs bundle when you navigate.

5. Create ScoreViewModel by using ViewModelProvider() as usual, except you’ll also pass in your ScoreViewModelFactory:

ViewModelProvider(this, viewModelFactory).get(ScoreViewModel::class.java)

By passing in the ViewModel factory, you're telling ViewModelProvider to use this factory to create ScoreViewModel.

6. Add a LiveData for the score and the play again event:

Create LiveData for score and eventPlayAgain using the best practices for encapsulation and event handling that you've learned. Make sure to initialize score’s value to the finalScore you pass into the view model.

7. Convert ScoreFragment to properly observe and use ScoreViewModel to update the UI:

In ScoreFragment, add observers for score and eventPlayAgain LiveData. Use them to update the UI.

Make sure to run your app, and confirm that everything is working!

If you want to start at this step, you can download this exercise code from: Step.07-Exercise-Add-a-ViewModelFactory.

You will find plenty of //TODO comments to help you complete this exercise, and if you get stuck, go back and watch the video again.

Once you’re done, you can check your solution against the solution we’ve provided here Step.07-Solution-Add-a-ViewModelFactory or using this git diff.

Task Description:

Check the steps below as you implement them to complete this exercise.

Task List:

Task Feedback:

Nice work! You can check your solution against the solution we’ve provided here Step.07-Solution-Add-a-ViewModelFactory or using this git diff.